package utility;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.InputMismatchException;
import java.util.Stack;
import java.util.Vector;

//the index is not attached or fixed to the task
//curr edit till undo edit only... problem is what if edit to an expired date.
// same thing for adding an expired date.

public class Editor implements EditorInterface {
	// private variables
	private Vector<Task> listOfTasks;
	private Vector<Task> tempVectorDisplay;
	private Vector<Task> overdueTasks;
	private Vector<Task> completedTasks;
	private Vector<Task> pastTasks;
	private String currDisplayType;
	private String[] currDisplayDates;
	private String currDisplayCompleted;
	private String[] completedDisplayDates;
	private String currDisplayOverdue;
	private String[] overdueDisplayDates;
	private Storage storageAccessor;
	private String currWord;
	private String currWordCompleted;
	private String currWordOverdue;
	private Vector<Task> todayTasks;
	private int currIndex;
	private Stack<Task> newEditedStack;
	private Stack<Task> undoStack;
	private Stack<Task> redoStack;

	// Constants
	private final String emptyString = "";
	private final String expectedDateFormat = "dd/MM/yy";
	private final String displayAllTasks = "allTasks";
	private final String displayAllFloating = "floatingTasks";
	private final String displayDateRange = "tasksWithinRange";
	private final String displayAllUserInput = "a";
	private final String displayFloatingUserInput = "f";
	private final String displayRangeUserInput = "r";
	private final String displaySearchWord = "search";
	private final String overdued = "overdue";
	private final String completed = "done";
	private final String undone = "undone";
	private final String addAction = "add";
	private final String deleteAction = "delete";
	private final String editAction = "edited";
	private final String setDoneAction = "setDone";
	private final String setUndoneAction = "setUndone";
	private final String emptyField = "-";
	private final int mainTasksPanel = 0;
	private final int completedTasksPanel = 1;
	private final int overduedTasksPanel = 2;
	private final int mainTasksVector = 0;
	private final int pastTasksVector = 1;
	private final int indexNotFound = -1;

	public Editor() {
		listOfTasks = new Vector<Task>();
		tempVectorDisplay = new Vector<Task>();
		completedTasks = new Vector<Task>();
		overdueTasks = new Vector<Task>();
		pastTasks = new Vector<Task>();
		currDisplayType = new String(emptyString);
		currDisplayDates = new String[2];
		currDisplayCompleted = new String(emptyString);
		completedDisplayDates = new String[2];
		currDisplayOverdue = new String(emptyString);
		overdueDisplayDates = new String[2];
		storageAccessor = new Storage();
		currWord = new String(emptyString);
		currWordCompleted = new String(emptyString);
		currWordOverdue = new String(emptyString);
		todayTasks = new Vector<Task>();
		currIndex = 0;
		undoStack = new Stack<Task>();
		newEditedStack = new Stack<Task>();
		redoStack = new Stack<Task>();
	}

	public void initEditor() {
		listOfTasks = storageAccessor.retrieveData();
		pastTasks = storageAccessor.retrieveHistory();
		if (listOfTasks.size() != 0) {
			currIndex = listOfTasks.get(listOfTasks.size() - 1).index;
		}
		getAllTasks(mainTasksPanel);
		getAllTasks(completedTasksPanel);
		getAllTasks(overduedTasksPanel);
	}

	public Vector<Task> retrieveTasks() throws ParseException {
		updateDisplayVector(mainTasksPanel);
		return tempVectorDisplay;
	}

	public Vector<Task> retrievePastTasks() throws ParseException {
		updateDisplayVector(overduedTasksPanel);
		return overdueTasks;
	}

	public Vector<Task> retrieveCompletedTasks() throws ParseException {
		updateDisplayVector(completedTasksPanel);
		return completedTasks;
	}

	// todays task.
	public Vector<Task> getTodayTasks(String todayDate) throws ParseException {

		todayTasks.clear();
		for (int i = 0; i < listOfTasks.size(); i++) {
			Task temp = listOfTasks.get(i);
			if (isWithinDateRange(temp.startDate, temp.endDate, todayDate,
					todayDate))
				todayTasks.add(temp);
		}
		sortTasks(todayTasks);
		return todayTasks;
	}

	public void addTask(UserInput inputs) throws IOException{
		Task currTask = new Task();

		currTask = assignValues(inputs, currTask);
		currTask.index = ++currIndex;
		listOfTasks.add(currTask);
		currTask.actionsMade = addAction;
		undoStack.push(currTask);
		sortTasks(listOfTasks);
		storageAccessor.writeFile(listOfTasks);
		redoStack.clear();
	}

	public void deleteTask(UserInput inputs) throws IOException {
		int currTab = inputs.panelNumber;
		int index = inputs.rowNumber;

		if (currTab == mainTasksPanel) {
			if (index <= tempVectorDisplay.size()) {
				deleteFromMainTasks(index);
			}
		} else if (currTab == completedTasksPanel) {
			if (index <= completedTasks.size()) {
				deleteFromPastTasks(index, currTab);
			}
		} else if (currTab == overduedTasksPanel) {
			if (index <= overdueTasks.size()) {
				deleteFromPastTasks(index, currTab);
			}
		}

		redoStack.clear();
	}

	public void displayTasks(UserInput inputs) throws ParseException{
		int currTab = inputs.panelNumber;

		String option = inputs.displayType;

		switch (option) {
		case displayFloatingUserInput: // view all floating tasks
			getAllFloatingTasks(currTab);
			break;
		case displayRangeUserInput: // view by date range
			getAllTasksWithinRange(inputs, currTab);
			break;
		case displayAllUserInput: // vew all
			getAllTasks(currTab);
		default:
			assert false : option;
		}

		if (currTab == mainTasksPanel) {
			sortTasks(tempVectorDisplay);
		} else if (currTab == completedTasksPanel) {
			sortTasks(completedTasks);
		} else if (currTab == overduedTasksPanel) {
			sortTasks(overdueTasks);
		}
	}

	public void editTask(UserInput inputs) throws IOException, ParseException,InvalidOperationException {
		int index = inputs.rowNumber;
		int currTab = inputs.panelNumber;

		if (currTab == mainTasksPanel) {
			if (index <= tempVectorDisplay.size()) {
				editTaskInCurrTab(inputs, index, currTab);
			}
		} else if (currTab == overduedTasksPanel) {
			if (index <= overdueTasks.size()) {
				editTaskInCurrTab(inputs, index, currTab);
			}
		}

		redoStack.clear();
		storageAccessor.writeFile(listOfTasks);
		storageAccessor.writePastTasks(pastTasks);
	}

	public void searchWord(UserInput inputs) {

		int currTab = inputs.panelNumber;
		assignDisplayType(inputs, currTab, displaySearchWord);

		if (currTab == mainTasksPanel) {
			searchInMainTasksVector(inputs);
		} else {
			assert (currTab == completedTasksPanel || currTab == overduedTasksPanel) : currTab;
			searchInPastTasksVector(inputs, currTab);
		}
	}

	public void setDone(UserInput input) throws IOException{
		int index = input.rowNumber;
		int currTab = input.panelNumber;
		if (currTab == mainTasksPanel || currTab == overduedTasksPanel) {
			Task tempTask = setATaskInCurrTabDone(index, currTab);
			tempTask.status = completed;
			tempTask.actionsMade = setDoneAction;
			undoStack.push(tempTask);
			sortTasks(pastTasks);
			redoStack.clear();
			storageAccessor.writePastTasks(pastTasks);
			storageAccessor.writeFile(listOfTasks);
		}
	}

	public void setUndone(UserInput input) throws IOException{
		int index = input.rowNumber;
		int currTab = input.panelNumber;
		if (currTab == completedTasksPanel) {
			Task temp = completedTasks.remove(index - 1);
			pastTasks.remove(getIndexOfTask(temp, pastTasksVector));
			temp.status = undone;
			listOfTasks.add(temp);
			sortTasks(listOfTasks);

			temp.actionsMade = setUndoneAction;
			undoStack.push(cloneTask(temp));
			redoStack.clear();
			storageAccessor.writeFile(listOfTasks);
			storageAccessor.writePastTasks(pastTasks);
		}
	}

	public void undoPrevious() throws ParseException, IOException {
		if (!undoStack.isEmpty()) {
			Task prevChangedTasks = undoStack.pop();
			Task undoingTask = cloneTask(prevChangedTasks);
			undoInCurrTab(prevChangedTasks);
			redoStack.push(undoingTask);
		}
	}

	public void redo() throws ParseException, IOException {
		if (!redoStack.isEmpty()) {
			Task prevUndoneTasks = redoStack.pop();
			Task redoingTask = cloneTask(prevUndoneTasks);
			redoInCurrTab(prevUndoneTasks);
			undoStack.push(redoingTask);
		}
	}

	public void update(String todayDate) throws IOException, ParseException {

		SimpleDateFormat format = new SimpleDateFormat(expectedDateFormat);
		Date currDate = format.parse(todayDate);

		updateMainTasksPanel(format, currDate);
		sortTasks(pastTasks);
		updateOverduedTasksPanel(format, currDate);

		sortTasks(listOfTasks);
		storageAccessor.writeFile(listOfTasks);
		storageAccessor.writePastTasks(pastTasks);
	}

	private void sortTasks(Vector<Task> sortedVector) {
		Collections.sort(sortedVector, new SortDate());
	}

	private Task assignValues(UserInput inputs, Task currTask) {
		if (!inputs.startD.isEmpty())
			currTask.startDate = inputs.startD;
		if (!inputs.startT.isEmpty())
			currTask.startTime = inputs.startT;
		if (!inputs.endD.isEmpty())
			currTask.endDate = inputs.endD;
		if (!inputs.endT.isEmpty())
			currTask.endTime = inputs.endT;
		if (!inputs.task.isEmpty())
			currTask.task = inputs.task;

		return currTask;
	}

	private void deleteFromMainTasks(int index) throws IOException {
		Task rmvTask = tempVectorDisplay.remove(index - 1);
		Task tempTask = cloneTask(listOfTasks.remove(getIndexOfTask(rmvTask,
				mainTasksVector)));
		tempTask.actionsMade = deleteAction;
		undoStack.push(tempTask);
		storageAccessor.writeFile(listOfTasks);
	}

	private void deleteFromPastTasks(int index, int currTab) {
		Task tempTask;
		if (currTab == completedTasksPanel)
			tempTask = completedTasks.remove(index - 1);
		else {
			assert currTab == overduedTasksPanel : currTab;
			tempTask = overdueTasks.remove(index - 1);
		}
		tempTask.actionsMade = deleteAction;
		undoStack.push(tempTask);
		pastTasks.remove(getIndexOfTask(tempTask, pastTasksVector));
		storageAccessor.writePastTasks(pastTasks);
	}

	private int getIndexOfTask(Task currTask, int vectorType) {
		int i = indexNotFound;
		if (vectorType == mainTasksVector) {
			for (Task t : listOfTasks) {
				i++;
				if (isSame(t, currTask))
					return i;
			}
		} else if (vectorType == pastTasksVector) {
			for (Task t : pastTasks) {
				i++;
				if (isSame(t, currTask))
					return i;
			}
		}
		i = indexNotFound;
		return i;
	}

	private boolean isSame(Task t, Task currTask) {
		if (!t.startTime.equals(currTask.startTime))
			return false;
		if (!t.endTime.equals(currTask.endTime))
			return false;
		if (!t.startDate.equals(currTask.startDate))
			return false;
		if (!t.endDate.equals(currTask.endDate))
			return false;
		if (!t.task.equals(currTask.task))
			return false;
		if (t.index != currTask.index)
			return false;
		return true;
	}

	private void getAllTasks(int currTab) {
		assignDisplayType(new UserInput(), currTab, displayAllTasks);

		if (currTab == mainTasksPanel) {
			for (Task t : listOfTasks) {
				tempVectorDisplay.add(t);
			}
		} else if (currTab == completedTasksPanel
				|| currTab == overduedTasksPanel) {
			for (Task t : pastTasks) {
				if (t.status.equals(completed)
						&& currTab == completedTasksPanel) {
					completedTasks.add(t);
				} else if (t.status.equals(overdued)
						&& currTab == overduedTasksPanel) {
					overdueTasks.add(t);
				}
			}
		}
	}

	private void getAllTasksWithinRange(UserInput inputs, int currTab)
			throws ParseException {

		assignDisplayType(new UserInput(), currTab, displayDateRange);

		String startRange = inputs.startD.trim();
		String endRange = inputs.endD.trim();
		if (startRange.isEmpty())
			startRange = endRange;

		if (currTab == mainTasksPanel) {
			currDisplayDates[0] = startRange;
			currDisplayDates[1] = endRange;
			for (Task t : listOfTasks) {
				String startDate = t.startDate;
				String endDate = t.endDate;
				if (isWithinDateRange(startDate, endDate, startRange, endRange)) {
					tempVectorDisplay.add(t);
				}
			}
		} else if (currTab == completedTasksPanel
				|| currTab == overduedTasksPanel) {
			if (currTab == completedTasksPanel) {
				completedDisplayDates[0] = startRange;
				completedDisplayDates[1] = endRange;
			} else {
				overdueDisplayDates[0] = startRange;
				overdueDisplayDates[1] = endRange;
			}
			for (Task t : pastTasks) {
				String startDate = t.startDate;
				String endDate = t.endDate;
				if (isWithinDateRange(startDate, endDate, startRange, endRange)
						&& currTab == completedTasksPanel) {
					if (t.status.equals(completed))
						completedTasks.add(t);
				} else if (isWithinDateRange(startDate, endDate, startRange,
						endRange) && currTab == overduedTasksPanel) {
					if (t.status.equals(overdued))
						overdueTasks.add(t);
				}
			}
		}
	}

	private boolean isWithinDateRange(String startDate, String endDate,
			String startRange, String endRange) throws ParseException {
		SimpleDateFormat format = new SimpleDateFormat(expectedDateFormat);
		Date startDateNew = null, endDateNew = null;

		if (startDate.equals(emptyField) && endDate.equals(emptyField))
			return false;
		else if (!startDate.equals(emptyField)) {
			startDateNew = format.parse(startDate);
		}

		if (!endDate.equals(emptyField)) {
			endDateNew = format.parse(endDate);
		} else if (!startDate.equals(emptyField))
			endDateNew = startDateNew;

		Date startRangeNew = format.parse(startRange);
		Date endRangeNew = format.parse(endRange);

		if (startDate.equals(emptyField)) {
			return compareDates(endDateNew, startRangeNew, endRangeNew);
		} else {
			if (!compareDates(startDateNew, startRangeNew, endRangeNew)) {
				return compareDates(endDateNew, startRangeNew, endRangeNew);
			} else
				return true;
		}
	}

	private boolean compareDates(Date date, Date start, Date end) {
		if ((date.compareTo(start) >= 0) && (date.compareTo(end) <= 0)) {
			return true;
		} else {
			assert date.compareTo(start) < 0 || date.compareTo(end) > 0 : date;

			return false;
		}
	}

	private void getAllFloatingTasks(int currTab) {
		assignDisplayType(new UserInput(), currTab, displayAllFloating);

		if (currTab == mainTasksPanel) {
			for (Task t : listOfTasks) {
				// if there is no start date and end date
				if (t.startDate.equals(emptyField)
						&& t.endDate.equals(emptyField))
					tempVectorDisplay.add(t);
			}
		} else if (currTab == completedTasksPanel
				|| currTab == overduedTasksPanel) {
			for (Task t : pastTasks) {
				if (t.startDate.equals(emptyField)
						&& t.endDate.equals(emptyField)) {
					if (currTab == completedTasksPanel
							&& t.status.equals(completed))
						completedTasks.add(t);
					else if (currTab == overduedTasksPanel
							&& t.status.equals(overdued))
						overdueTasks.add(t);
				}
			}
		}
	}

	private void editTaskInCurrTab(UserInput inputs, int index, int currTab)
			throws ParseException, InvalidOperationException {
		Task chosenTask = getTask(index, currTab);
		Task editedTask = assignValues(inputs, chosenTask);
		checkNewTask(editedTask);
		updateListOfTasks(editedTask, index, currTab);
	}


	private Task getTask(int index, int currTab) {
		Task currTask;

		if (currTab == mainTasksPanel)
			currTask = tempVectorDisplay.get(index - 1);
		else {
			assert currTab == overduedTasksPanel : currTab;
			currTask = overdueTasks.get(index - 1);
		}
		Task temp = cloneTask(currTask);
		temp.actionsMade = editAction;
		currTask.actionsMade = editAction;
		undoStack.push(currTask);

		return temp;
	}

	private void checkNewTask(Task editedTask) throws InvalidOperationException, ParseException {
		if(hasSameDate(editedTask)){
			undoStack.pop();
			throw new InvalidOperationException("Unable to Edit: End date cannot be the same as start date.");
		}else if(hasOnlyStartDate(editedTask)){
			undoStack.pop();
			throw new InvalidOperationException("Unable to Edit: Cannot have start date without end date.");
		}else if(hasOnlyStartTime(editedTask)){
			undoStack.pop();
			throw new InvalidOperationException("Unable to Edit: Cannot have start time without end time.");
		}else if(hasTimeNoDate(editedTask)){
			undoStack.pop();
			throw new InvalidOperationException("Unable to Edit: Cannot have a time without a date.");
		}else if(hasSameTime(editedTask)){
			undoStack.pop();
			throw new InvalidOperationException("Unable to Edit: End time cannot be the same as start time.");
		}else if(isStartTimeLater(editedTask)){
			undoStack.pop();
			throw new InvalidOperationException("Unable to Edit: End time must be later than start time.");
		}else if(isStartDateLater(editedTask)){
			undoStack.pop();
			throw new InvalidOperationException("Unable to Edit: End date must be later than start date.");
		}
		}
	
	
	
	private boolean isStartDateLater(Task editedTask) throws ParseException {
		SimpleDateFormat format = new SimpleDateFormat("dd/MM/yy");
		String startDate = editedTask.startDate;
		String endDate = editedTask.endDate;
		
		if(startDate.equals(emptyField) || endDate.equals(emptyField))
			return false;
		
		Date start = format.parse(startDate);
		Date end = format.parse(endDate);
		if(start.after(end))
			return true;
		
		return false;
	}

	private boolean isStartTimeLater(Task editedTask) {
		if(!editedTask.endDate.equals(emptyField) && editedTask.startDate.equals(emptyField))
			if(editedTask.startTime.compareTo(editedTask.endTime) > 0)
				return true;
		return false;
	}

	private boolean hasTimeNoDate(Task editedTask) {
		if((!editedTask.startDate.equals(emptyField)) || (!editedTask.endDate.equals(emptyField)))
			return false;
		else if((!editedTask.startTime.equals(emptyField))|| (!editedTask.endTime.equals(emptyField)))
			return true;
		else 
			return false;
	}

	private boolean hasSameTime(Task editedTask) {
		if(!editedTask.endDate.equals(emptyField) && editedTask.startDate.equals(emptyField)){
			if(editedTask.startTime.equals(editedTask.endTime))
				return true;
		}
			return false;
	}

	private boolean hasOnlyStartTime(Task editedTask) {
		if(!editedTask.startTime.equals(emptyField) && editedTask.endTime.equals(emptyField)){
			if(editedTask.endDate.equals(emptyField))
				return true;
		}
			return false;
	}

	private boolean hasOnlyStartDate(Task editedTask) {
		if(!editedTask.startDate.equals(emptyField) && editedTask.endDate.equals(emptyField))
			return true;
		else
			return false;
	}

	private boolean hasSameDate(Task editedTask) throws ParseException {
		SimpleDateFormat format = new SimpleDateFormat("dd/MM/yy");
		String startDate = editedTask.startDate;
		String endDate = editedTask.endDate;
		
		if(startDate.equals(emptyField) || endDate.equals(emptyField))
			return false;
		
		Date start = format.parse(startDate);
		Date end = format.parse(endDate);
		if(start.equals(end))
			return true;
		
		return false;
	}

	

	private Task cloneTask(Task currTask) {
		Task tempTask = new Task();
		tempTask.startDate = currTask.startDate;
		tempTask.endDate = currTask.endDate;
		tempTask.startTime = currTask.startTime;
		tempTask.endTime = currTask.endTime;
		tempTask.task = currTask.task;
		tempTask.index = currTask.index;
		tempTask.status = currTask.status;
		tempTask.actionsMade = currTask.actionsMade;

		return tempTask;
	}

	private void updateListOfTasks(Task editedTask, int index, int currTab) {
		if (currTab == mainTasksPanel) {
			int actualIndex = getIndexOfTask(tempVectorDisplay.get(index - 1),
					mainTasksVector);
			tempVectorDisplay.set(index - 1, editedTask);
			listOfTasks.set(actualIndex, editedTask);
			sortTasks(listOfTasks);
		} else if (currTab == overduedTasksPanel) {
			int actualIndex = getIndexOfTask(overdueTasks.get(index - 1),
					pastTasksVector);
			overdueTasks.set(index - 1, editedTask);
			pastTasks.set(actualIndex, editedTask);
			sortTasks(pastTasks);
		}
		newEditedStack.push(editedTask);
	}

	private void assignDisplayType(UserInput inputs, int currTab,
			String displayType) {

		if (currTab == mainTasksPanel) {
			currDisplayType = new String(displayType);
			if (displayType.equals(displaySearchWord))
				currWord = inputs.keyword;
			tempVectorDisplay.clear();
		} else if (currTab == completedTasksPanel) {
			currDisplayCompleted = new String(displayType);
			if (displayType.equals(displaySearchWord))
				currWordCompleted = inputs.keyword;
			completedTasks.clear();
		} else if (currTab == overduedTasksPanel) {
			currDisplayOverdue = new String(displayType);
			if (displayType.equals(displaySearchWord))
				currWordOverdue = inputs.keyword;
			overdueTasks.clear();
		}
	}

	private void searchInMainTasksVector(UserInput inputs) {
		for (Task t : listOfTasks) {
			if (t.task.toLowerCase().contains(inputs.keyword.toLowerCase()))
				tempVectorDisplay.add(t);
		}
		sortTasks(tempVectorDisplay);
	}

	private void searchInPastTasksVector(UserInput inputs, int currTab) {
		for (Task t : pastTasks) {

			if (t.task.toLowerCase().contains(inputs.keyword.toLowerCase())) {
				if (t.status.equals(completed)
						&& currTab == completedTasksPanel)
					completedTasks.add(t);
				else if (t.status.equals(overdued)
						&& currTab == overduedTasksPanel)
					overdueTasks.add(t);
			}
		}

		if (currTab == completedTasksPanel)
			sortTasks(completedTasks);
		else {
			assert currTab == overduedTasksPanel : currTab;
			sortTasks(overdueTasks);
		}
	}

	private Task setATaskInCurrTabDone(int index, int currTab) {
		Task tempTask = null;
		if (currTab == mainTasksPanel && index <= tempVectorDisplay.size()) {
			Task taskDelete = tempVectorDisplay.remove(index - 1);
			tempTask = cloneTask(listOfTasks.remove(getIndexOfTask(taskDelete,
					mainTasksVector)));
			tempTask.status = completed;
			pastTasks.add(tempTask);
		} else if (currTab == overduedTasksPanel
				&& index <= overdueTasks.size()) {
			Task taskDelete = overdueTasks.remove(index - 1);
			tempTask = cloneTask(pastTasks.get(getIndexOfTask(taskDelete,
					pastTasksVector)));
			pastTasks.get(getIndexOfTask(taskDelete, pastTasksVector)).status = completed;

		}
		return tempTask;
	}

	// undo methods
	private void undoInCurrTab(Task prevChangedTask) throws ParseException,
			IOException {

		String actionDone = prevChangedTask.actionsMade;
		switch (actionDone) {
		case addAction:
			undoAdd(prevChangedTask);
			break;
		case deleteAction:
			undoDelete(prevChangedTask);
			break;
		case editAction:
			undoEdit(prevChangedTask);
			break;
		case setDoneAction:
			undoSetDone(prevChangedTask);
			break;
		case setUndoneAction:
			redoSetDone(prevChangedTask);
			break;
		default:
			throw new AssertionError(actionDone);
		}

		storageAccessor.writeFile(listOfTasks);
		storageAccessor.writePastTasks(pastTasks);
	}

	private void undoAdd(Task prevTask) {
		int index = getIndexOfTask(prevTask, mainTasksVector);
		if (index != indexNotFound)
			listOfTasks.remove(index);
		else {
			assert index == indexNotFound : index;
			index = getIndexOfTask(prevTask, pastTasksVector);
			if (index != indexNotFound) {
				pastTasks.remove(index);
			}
		}
	}

	private void undoDelete(Task prevTask) {
		if (prevTask.status.equals(undone)) {
			listOfTasks.add(prevTask);
			sortTasks(listOfTasks);
		} else if (prevTask.status.equals(overdued)
				|| prevTask.status.equals(completed)) {
			pastTasks.add(prevTask);
			sortTasks(pastTasks);
		}
	}

	private void undoEdit(Task prevTask) {
		Task newTask = newEditedStack.pop();
		redoStack.push(cloneTask(newTask));

		if (newTask.status.equals(undone)) {
			int index = getIndexOfTask(newTask, mainTasksVector);
			newTask = replaceTask(prevTask, newTask);
			listOfTasks.set(index, newTask);
			sortTasks(listOfTasks);
		} else if (newTask.status.equals(overdued)
				|| newTask.status.equals(completed)) {
			int index = getIndexOfTask(newTask, pastTasksVector);
			if (index != indexNotFound) {
				newTask = replaceTask(prevTask, newTask);
				pastTasks.set(index, newTask);
				sortTasks(pastTasks);
			}
		}
	}

	private Task replaceTask(Task prevTask, Task newTask) {
		newTask.startDate = prevTask.startDate;
		newTask.endDate = prevTask.endDate;
		newTask.startTime = prevTask.startTime;
		newTask.endTime = prevTask.endTime;
		newTask.task = prevTask.task;
		newTask.index = prevTask.index;
		newTask.status = prevTask.status;

		return newTask;
	}

	private void undoSetDone(Task prevTask) throws ParseException {
		prevTask.status = undone;
		listOfTasks.add(prevTask);
		sortTasks(listOfTasks);
		int index = getIndexOfTask(prevTask, pastTasksVector);
		if (index != indexNotFound)
			pastTasks.remove(index);
	}

	private void updateDisplayVector(int currTab) throws ParseException {
		UserInput temp = new UserInput();
		temp.panelNumber = currTab;
		String display = new String(emptyString);
		String word = new String(emptyString);

		display = getDisplayType(currTab, display);

		switch (display) {
		case displayAllTasks:
			temp.displayType = displayAllUserInput;
			displayTasks(temp);
			break;
		case displayDateRange:
			temp.displayType = displayRangeUserInput;
			if (currTab == mainTasksPanel) {
				temp.startD = currDisplayDates[0];
				temp.endD = currDisplayDates[1];
			} else if (currTab == completedTasksPanel) {
				temp.startD = completedDisplayDates[0];
				temp.endD = completedDisplayDates[1];
			} else {
				temp.startD = overdueDisplayDates[0];
				temp.endD = overdueDisplayDates[1];
			}
			displayTasks(temp);
			break;
		case displayAllFloating:
			temp.displayType = displayFloatingUserInput;
			displayTasks(temp);
			break;
		case displaySearchWord:
			temp.keyword = getSearchWord(currTab, word);
			searchWord(temp);
			break;
		default:
			throw new AssertionError(display);
		}

	}

	private String getDisplayType(int currTab, String display) {
		if (currTab == mainTasksPanel) {
			display = currDisplayType;
		} else if (currTab == completedTasksPanel) {
			display = currDisplayCompleted;
		} else if (currTab == overduedTasksPanel) {
			display = currDisplayOverdue;
		}
		return display;
	}

	private String getSearchWord(int currTab, String word) {
		if (currTab == mainTasksPanel) {
			word = currWord;
		} else if (currTab == completedTasksPanel) {
			word = currWordCompleted;
		} else if (currTab == overduedTasksPanel) {
			word = currWordOverdue;
		}
		return word;
	}

	// redo methods
	private void redoInCurrTab(Task undoneTask) throws ParseException,
			IOException {
		String actionDone = undoneTask.actionsMade;
		switch (actionDone) {
		case addAction:
			undoDelete(undoneTask);
			break;
		case deleteAction:
			undoAdd(undoneTask);
			break;
		case editAction:
			redoUndoneEdit(undoneTask);
			break;
		case setDoneAction:
			redoSetDone(undoneTask);
			break;
		case setUndoneAction:
			undoSetDone(undoneTask);
			break;
		default:
			throw new AssertionError(actionDone);
		}
		storageAccessor.writeFile(listOfTasks);
		storageAccessor.writePastTasks(pastTasks);
	}

	private void redoSetDone(Task undoneTask) {
		undoneTask.status = completed;
		if (getIndexOfTask(undoneTask, pastTasksVector) == indexNotFound) {
			pastTasks.add(undoneTask);
			sortTasks(pastTasks);

			int index = getIndexOfTask(undoneTask, mainTasksVector);
			if (index != indexNotFound)
				listOfTasks.remove(index);
		} else {
			assert getIndexOfTask(undoneTask, pastTasksVector) != indexNotFound : undoneTask;
			pastTasks.get(getIndexOfTask(undoneTask, pastTasksVector)).status = completed;
		}
	}

	private void redoUndoneEdit(Task undoneTask) {
		Task newTask = redoStack.pop();
		newEditedStack.push(cloneTask(newTask));
		if (newTask.status.equals(undone)) {
			int index = getIndexOfTask(undoneTask, mainTasksVector);
			if (index != indexNotFound) {
				newTask = replaceTask(newTask, undoneTask);
				listOfTasks.set(index, newTask);
				sortTasks(listOfTasks);
			}
		}

		else if (newTask.status.equals(completed)
				|| newTask.status.equals(overdued)) {
			int index = getIndexOfTask(undoneTask, pastTasksVector);
			if (index != indexNotFound) {
				newTask = replaceTask(newTask, undoneTask);
				pastTasks.set(index, newTask);
				sortTasks(pastTasks);
			}
		}

	}

	private void updateOverduedTasksPanel(SimpleDateFormat format, Date currDate)
			throws ParseException {
		Date endDate;
		for (int i = 0; i < overdueTasks.size(); i++) {
			Task t = overdueTasks.get(i);
			if (!t.endDate.equals(emptyField)) {
				endDate = format.parse(t.endDate);
				if ((currDate.compareTo(endDate) <= 0)) {
					pastTasks.remove(getIndexOfTask(overdueTasks.remove(i),
							pastTasksVector));
					t.status = undone;
					listOfTasks.add(t);
					tempVectorDisplay.add(t);
					i--;
				}
			}
		}
	}

	private void updateMainTasksPanel(SimpleDateFormat format, Date currDate)
			throws ParseException {
		Date endDate;
		for (int i = 0; i < listOfTasks.size(); i++) {
			Task t = listOfTasks.get(i);

			if (!t.endDate.equals(emptyField)) {
				endDate = format.parse(t.endDate);
				if ((currDate.compareTo(endDate) > 0)) {
					listOfTasks.remove(i);
					t.status = overdued;
					pastTasks.add(t);
					i--;
				}
			}
		}
	}

	// for unit Testing from here on

	public String jUnitTest() {
		String temp = new String(emptyString);
		for (int i = 0; i < tempVectorDisplay.size(); i++) {
			temp += concateTask(tempVectorDisplay.get(i));
		}
		return temp;
	}

	public String jUnitPastTasks() {
		String temp = new String(emptyString);
		for (Task t : pastTasks) {
			temp += concateTask(t);
			temp += ";" + t.status;
		}
		return temp;
	}

	public String jUnitCompletedTasks() {
		String temp = new String(emptyString);
		for (Task t : completedTasks) {
			if (t.status.equals(completed)) {
				temp += concateTask(t);
				temp += ";" + t.status;
			}
		}
		return temp;
	}

	public String jUnitOverdueTasks() {
		String temp = new String(emptyString);
		for (Task t : overdueTasks) {
			if (t.status.equals(overdued)) {
				temp += concateTask(t);
				temp += ";" + t.status;
			}
		}
		return temp;
	}

	public void setEnvironmentForTest(){
		storageAccessor.setTestingEnvironment();
	}
	
	private String concateTask(Task tempTask) {
		String concatedTask = new String(emptyString);
		concatedTask += tempTask.startDate + ";";
		concatedTask += tempTask.endDate + ";";
		concatedTask += tempTask.startTime + ";";
		concatedTask += tempTask.endTime + ";";
		concatedTask += tempTask.task;
		return concatedTask;
	}
	
}
